# todo 这里是用户添加的app
from datetime import datetime
from marshmallow import ValidationError
from models import db, App
from flask import request

from utils import ThreadLocal
from .validate import addApp, updateApp, queryApp, reviewApp
from my_decorator.AuthCheck import auth_check
from common.ApiResponse import ApiResponse
from common.BaseResponse import BaseResponse
from common.ErrorCode import ErrorCode
from constant import UserConstant

# 检验数据模型
add_app = addApp()
query_app = queryApp()
review_app = reviewApp()
update_app = updateApp()


@auth_check(required_roles=[UserConstant.DEFAULT_ROLE, UserConstant.ADMIN_ROLE])
def addApp():
    # 1.从前端获取app的相关信息-->json
    # 2.验证app信息
    try:
        app_info = add_app.load(request.json)
    except ValidationError as err:
        error_response = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data=first_value[0]
        )

    # 2.1 表单验证通过将该app的信息提交到数据库
    # 2.1.1 获取app信息
    appName = app_info['appName']
    appDesc = app_info['appDesc']
    appType = app_info['appType']
    appIcon = app_info['appIcon']
    scoringStrategy = app_info['scoringStrategy']
    # 2.1.2 获取当前登录的用户信息
    user_map = ThreadLocal.ThreadLocalUtil.get()
    # 2.1.3 创建App对象
    app = App(
        appName=appName,
        appType=appType,
        appDesc=appDesc,
        appIcon=appIcon,
        scoringStrategy=scoringStrategy,
        userId=user_map['id']
    )
    # 2.2 将上述信息提交至数据库
    db.session.add(app)
    db.session.commit()
    # 2.3 向前端响应数据
    return ApiResponse.success(data=f"{app.id}")


@auth_check(required_roles=[UserConstant.DEFAULT_ROLE, UserConstant.ADMIN_ROLE])
def deleteApp():
    # 1.获取前端传递的数据-->/app/delete?app_id=<app_id>
    # 2.验证数据的合法性
    app_id = int(request.args.get('id'))
    if not app_id or (app_id and app_id <= 0):
        # 2.1 app_id 数值不合法
        errorResponse = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
        return ApiResponse.error_from_baseResponse(baseResponse=errorResponse, data="app_id:数值不合法")
    else:
        # 2.2 判断当前用户是否存在该app_id
        user_map = ThreadLocal.ThreadLocalUtil.get()
        app_id = int(app_id)
        app = App.query.filter_by(id=app_id).first()
        if app.userId == user_map['id'] or user_map['user_role'] == UserConstant.ADMIN_ROLE:
            if app.isDelete == 1:
                app.isDelete = 0
                db.session.commit()
                return ApiResponse.success(data=f"已成功将该编号为{app_id}的app恢复！")
            else:
                app.isDelete = 1
                db.session.commit()
                return ApiResponse.success(data=f"已成功将该编号为{app_id}的app删除！")
        else:
            # 2.2.2.2 当前用户权限不足，不能被删除
            errorResponse = BaseResponse.from_error_code(ErrorCode.NO_AUTH_ERROR)
            return ApiResponse.error_from_baseResponse(
                baseResponse=errorResponse,
                data="权限不足，无法进行该操作"
            )


@auth_check(required_roles=[UserConstant.ADMIN_ROLE, UserConstant.DEFAULT_ROLE])
def updateApp():
    # 1.验证前端数据json的合法性
    try:
        app_data = update_app.load(request.json)
    except ValidationError as err:
        error_response = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data=first_value[0]
        )
    # 2.查找指定的app并更新相关信息
    old_app = App.query.filter_by(id = app_data.get('id')).first()
    # 2.1 权限问题
    user_map = ThreadLocal.ThreadLocalUtil.get()
    update_fields_default = {
        'appName': lambda v: {'appName': v},
        'appType': lambda v: {'appType': v},
        'appDesc': lambda v: {'appDesc': v},
        'appIcon': lambda v: {'appIcon': v},
        'scoringStrategy': lambda v: {'scoringStrategy': v},
        'isDelete': lambda v: {'isDelete': v}
    }
    update_fields_admin = {
        'reviewStatus': lambda v: {'reviewStatus': v},
        'reviewMessage': lambda v: {'reviewMessage': v},
        'reviewerId': lambda v: {'reviewerId': v},
    }

    if old_app.userId == user_map['id'] or user_map['user_role'] == UserConstant.ADMIN_ROLE:
        for field, func in update_fields_default.items():
            value = app_data.get(field)
            if value is not None:
                App.query.filter_by(id=app_data.get('id')).update(func(value))
        if user_map.get('user_role') == 'admin':
            for field, func in update_fields_admin.items():
                value = app_data.get(field)
                if value is not None:
                    App.query.filter_by(id=app_data.get('id')).update(func(value))
        old_app.updateTime = datetime.now()
        db.session.commit()
        return ApiResponse.success(data=f"成功将appName为{app_data['appName']}的app进行修改")
    else:
        errorResponse = BaseResponse.from_error_code(
            ErrorCode.NO_AUTH_ERROR
        )
        return ApiResponse.error_from_baseResponse(
            baseResponse=errorResponse,
            data=f"当前用户不存在该app"
        )


@auth_check(required_roles=[UserConstant.ADMIN_ROLE, UserConstant.DEFAULT_ROLE])
def getApp():
    # 1.获取前端提交的数据-->/app/get?app_id=<app_id>
    app_id = int(request.args.get('id'))
    # 2.在当前用户的app集中寻找该app
    user_map = ThreadLocal.ThreadLocalUtil.get()
    app = App.query.filter_by(id=app_id, isDelete=0).first()
    if not app:
        # 2.1 当前用户app集中不存在该app 或 被移入‘回收站’
        errorResponse = BaseResponse.from_error_code(
            ErrorCode.NOT_FOUND_ERROR
        )
        return ApiResponse.error_from_baseResponse(
            baseResponse=errorResponse,
            data="该app不存在 或 已被移入‘回收站’"
        )
    else:
        # 2.2 当前用户app集中存在该app 并且 未被移入‘回收站’
        return ApiResponse.success(
            data=app.to_json_VO()
        )


@auth_check(required_roles=[UserConstant.ADMIN_ROLE, UserConstant.DEFAULT_ROLE])
def listAppByPage():
    # 1.获取前端提交的数据-->json
    data = request.json
    for key in ["pageSize", "current", "sortField", "sortOrder"]:
        if data.get(key) is None:
            data[key] = query_app.fields[key].default

    try:
        query_data = query_app.load(data)
    except ValidationError as err:
        error_response = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data=first_value[0]
        )

    # 2.验证通过，按条件查询数据
    # 数据库查询 + 分页
    user_map = ThreadLocal.ThreadLocalUtil.get()
    pagination = query_database(query_data=query_data, user_map=user_map)
    # 2.4 返回结果
    base_data = {
        "total": pagination.total,
        "pages": pagination.pages,
        "current": pagination.page,
        "pageSize": pagination.per_page
    }
    print(user_map.get('user_role'))
    if user_map.get('user_role') == 'admin':
        base_data['apps'] = [app.to_json_admin() for app in pagination.items]
    else:
        base_data['apps'] = [app.to_json_VO() for app in pagination.items]
    return ApiResponse.success(data=base_data)


def listMyAppByPage():
    # 1.获取前端提交的数据-->json
    data = request.json
    for key in ["pageSize", "current", "sortField", "sortOrder"]:
        if data.get(key) is None:
            data[key] = query_app.fields[key].default
    try:
        query_data = query_app.load(data)
    except ValidationError as err:
        error_response = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data=first_value[0]
        )
    # 2.验证通过，按条件查询数据
    # 数据库查询 + 分页
    user_map = ThreadLocal.ThreadLocalUtil.get()
    pagination = query_database(query_data=query_data, user_map=user_map, isMy=True)
    # 3.返回结果
    data = {
        "total": pagination.total,
        "pages": pagination.pages,
        "current_page": pagination.page,
        "pageSize": pagination.per_page,
        'apps': [app.to_json_VO() for app in pagination.items]
    }
    return ApiResponse.success(data=data)


def query_database(query_data: query_app, user_map, isMy: bool = False):
    #
    pageSize = query_data.get('pageSize')
    pageNum = query_data.get('current')

    if user_map.get('user_role') == 'user':  # 防止爬虫
        if pageSize > 20:
            errorResponse = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
            return ApiResponse.error_from_baseResponse(errorResponse)
    # 2.1 创建基础查询对象
    query = App.query

    if isMy:
        # todo 这个地方其实也不一定吧,普通用户那只能看到自己的？
        query = query.filter(App.userId == user_map.get('id'))
    # 2.2 增添查询条件
    and_fields = {
        'appName': lambda q, v: q.filter(App.appName.contains(v)),
        'appDesc': lambda q, v: q.filter(App.appDesc.contains(v)),
        'appType': lambda q, v: q.filter(App.appType == v),
        'scoringStrategy': lambda q, v: q.filter(App.scoringStrategy == v),
        'isDelete': lambda q, v: q.filter(App.isDelete == v),
        'reviewStatus': lambda q, v: q.filter(App.reviewStatus == v),
        'reviewMessage': lambda q, v: q.filter(App.reviewMessage.contains(v)),
        'reviewerId': lambda q, v: q.filter(App.reviewerId == v)
    }
    # 2.2.1 动态构建’和‘查询
    for field, condition_func in and_fields.items():
        value = query_data.get(field)
        if value is not None:
            query = condition_func(query, value)
    # 2.2.2 动态排序字段
    sort_fields = {
        'id': App.id,
        'appName': App.appName,
        'appDesc': App.appDesc,
        'appType': App.appType,
        'scoringStrategy': App.scoringStrategy,
        'reviewStatus': App.reviewStatus,
        'reviewMessage': App.reviewMessage,
        'reviewerId': App.reviewerId,
        'createTime': App.createTime,
        'updateTime': App.updateTime
    }
    field_name = query_data.get("sortField")
    if field_name:  # 仅可以指定一个排序字段
        direction = query_data.get('sortOrder')
        column = sort_fields.get(field_name)
        if direction == 'desc':
            column = column.desc()
        else:
            column = column.asc()
        query = query.order_by(column)
    # 返回查询结果
    return query.paginate(page=pageNum, per_page=pageSize)


@auth_check(required_roles=[UserConstant.ADMIN_ROLE])
def reviewApp():
    # 1.从前端获取数据 -->json，并验证数据的合法性
    try:
        review_data = review_app.load(request.json)
    except ValidationError as err:
        error_response = BaseResponse.from_error_code(ErrorCode.PARAMS_ERROR)
        first_key, first_value = next(iter(err.messages.items()))
        return ApiResponse.error_from_baseResponse(
            baseResponse=error_response,
            data=first_value[0]
        )

    # 2.解析数据，并提交至数据库
    # 2.1 解析数据
    appId = review_data.get('appId')
    reviewStatus = review_data.get('reviewStatus')
    reviewMessage = review_data.get('reviewMessage')
    # 2.2 更新数据库
    user_map = ThreadLocal.ThreadLocalUtil.get()

    reviewing_app = App.query.get(appId)
    reviewing_app.reviewStatus = reviewStatus
    reviewing_app.reviewMessage = reviewMessage
    reviewing_app.reviewerId = user_map.get('id')
    reviewing_app.reviewTime = datetime.now()
    db.session.commit()
    # 3.向前端响应数据
    return ApiResponse.success(data="审核成功！")
